/*
 * UnaryClosure.java
 *
 * Created on July 23, 2006, 8:26 PM
 *
 */

package galronnlp.pcfg.parser;

import galronnlp.math.IdentityMatrix;
import galronnlp.math.Matrix;
import galronnlp.math.MatrixIndexException;
import galronnlp.math.MatrixSizeException;
import galronnlp.util.Grammar;
import galronnlp.util.Symbol;
import galronnlp.util.SymbolGenerator;
import galronnlp.util.Tuple;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;

/**
 *
 * @author Daniel A. Galron
 */
public class UnaryClosure {
    
    private Matrix Pu;
    private Matrix Ru;
    
    private IdentityMatrix Im;
    
    LinkedList<Symbol> index = new LinkedList<Symbol>();
    
    /** Creates a new instance of UnaryClosure */
    public UnaryClosure(Grammar g) {
        this.indexNonTerminals(g);
        Pu = new Matrix(index.size(), index.size());
        Ru = new Matrix(index.size(), index.size());
        Im = new IdentityMatrix(index.size());
        for(Enumeration<Symbol> RHSenum = g.unaryRules.keys(); RHSenum.hasMoreElements(); ) {
            Symbol RHS = RHSenum.nextElement();
            LinkedList<Tuple> LHSTup = g.unaryRules.get(RHS);
            for(Iterator<Tuple> LHSit = LHSTup.iterator(); LHSit.hasNext(); ) {
                Tuple tup = LHSit.next();
                Symbol LHS = (Symbol)tup.get(0);
                double prob = ((Double)tup.get(1)).doubleValue();
                try {
                    System.out.println(LHS + ", " + RHS + ": " + prob);
                    Pu.put(index.indexOf(LHS), index.indexOf(RHS), prob);
                } catch (MatrixIndexException ex) {
                    ex.printStackTrace();
                }
            }
        }
        Matrix tmp = new Matrix(1,1);
        try {
            tmp = Im.sub(Pu);
        } catch (MatrixSizeException ex) {
            ex.printStackTrace();
        }
        System.out.println("-- Pu --");
        System.out.println(Pu);
        System.out.println("--------");
        Ru = tmp.inverse();
        System.out.println("-- Ru --");
        System.out.println(Ru);
        System.out.println("--------");
    }

    public Hashtable<Symbol, LinkedList<Tuple>> getUnaryClosure() {
        Hashtable<Symbol, LinkedList<Tuple>> unaryRules = new Hashtable<Symbol, LinkedList<Tuple>>();
        for(int j = 0; j < index.size(); j++) {
            LinkedList<Tuple> LHS = new LinkedList<Tuple>();
            for(int i = 0; i < index.size(); i++) {
                double prob = 0;
                try {
                    prob = Ru.get(i, j);
                } catch (MatrixIndexException ex) {
                    ex.printStackTrace();
                }
                if(i == j) {
                    prob -= 1.0;
                }
                if(prob >= 1e-20) {
                    Tuple tup = new Tuple(2);
                    tup.put(0, index.get(i));
                    tup.put(1, new Double(prob));
                    LHS.addLast(tup);
                }
            }
            unaryRules.put(index.get(j), LHS);
        }
        return unaryRules;
    }
    
    private void indexNonTerminals(Grammar g) {
        for(Enumeration<Symbol> RHSenum = g.unaryRules.keys(); RHSenum.hasMoreElements(); ) {
            Symbol RHS = RHSenum.nextElement();
            LinkedList<Tuple> LHSTup = g.unaryRules.get(RHS);
            if(!index.contains(RHS))
                index.addLast(RHS);
            for(Iterator<Tuple> LHSit = LHSTup.iterator(); LHSit.hasNext(); ) {
                Tuple tup = LHSit.next();
                Symbol LHS = (Symbol)tup.get(0);
                double prob = ((Double)tup.get(1)).doubleValue();
                if(!index.contains(LHS))
                    index.addLast(LHS);
            }
        }
    }
}
